package com.neasho.neashoadminv1.web.service.sys

import com.neasho.neashoadminv1.infrastructure.domain.YesOrNo
import com.neasho.neashoadminv1.infrastructure.domain.sys.SysUser
import com.neasho.neashoadminv1.infrastructure.domain.sys.delFlag
import com.neasho.neashoadminv1.infrastructure.domain.sys.id
import com.neasho.neashoadminv1.infrastructure.dto.sys.*
import com.neasho.neashoadminv1.infrastructure.exception.BusinessCode
import com.neasho.neashoadminv1.infrastructure.exception.BusinessException
import org.babyfish.jimmer.Specification
import org.babyfish.jimmer.View
import org.babyfish.jimmer.spring.repository.fetchSpringPage
import org.babyfish.jimmer.spring.repository.orderBy
import org.babyfish.jimmer.sql.ast.mutation.AssociatedSaveMode
import org.babyfish.jimmer.sql.ast.mutation.SaveMode
import org.babyfish.jimmer.sql.kt.KSqlClient
import org.babyfish.jimmer.sql.kt.ast.expression.`eq?`
import org.babyfish.jimmer.sql.kt.ast.mutation.KDeleteResult
import org.babyfish.jimmer.sql.kt.ast.mutation.KSimpleSaveResult
import org.slf4j.LoggerFactory
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import kotlin.reflect.KClass

@Service
class SysUserService(
    private val sqlClient: KSqlClient,
    private val sysUserTokenService: SysUserTokenService
){
    private val log = LoggerFactory.getLogger(SysUserService::class.java)
    private val entityClass = SysUser::class

    fun <V : View<SysUser>> page(spec: Specification<SysUser>, viewType: KClass<V>, pageable: Pageable): Page<V> {
        return sqlClient.createQuery(entityClass) {
            where(spec)
            orderBy(pageable.sort)
            select(table.fetch(viewType))
        }.fetchSpringPage(pageable)
    }

    fun save(input: SysUserAddInput): KSimpleSaveResult<SysUser> {
        return sqlClient.save(input)
    }

    fun update(input: SysUserAddInput): KSimpleSaveResult<SysUser> {
        return sqlClient.save(input)
    }

    fun deleteByLogic(id: Long): Int {
        return sqlClient.executeUpdate(entityClass) {
            set(table.delFlag, YesOrNo.yes)
            where(table.id `eq?` id)
        }
    }

    fun deleteByPhysical(id: Long): KDeleteResult {
        return sqlClient.deleteById(entityClass, id)
    }

    fun batchDeleteByIds(ids: List<Long>): KDeleteResult {
        return sqlClient.deleteByIds(entityClass, ids)
    }

    fun <V:View<SysUser>> findById(spec: SysUserDetailSpec, viewType: KClass<V>) : V? {
        return sqlClient.executeQuery(entityClass) {
            where(spec)
            select(table.fetch(viewType))
        }.firstOrNull()
    }

    fun <V:View<SysUser>> list(spec: SysUserListSpec, viewType: KClass<V>) : List<V> {
        return sqlClient.executeQuery(entityClass) {
            where(spec)
            select(table.fetch(viewType))
        }
    }

    @Transactional
    fun batchUpdate(list:List<SysUserUpdateInput>) : Int {
        return sqlClient.entities.saveInputs(list, SaveMode.UPDATE_ONLY, AssociatedSaveMode.REPLACE).totalAffectedRowCount
    }

    @Transactional
    fun batchSave(list: List<SysUserAddInput>) : Int {
        return sqlClient.entities.saveInputs(list, SaveMode.INSERT_ONLY, AssociatedSaveMode.MERGE).totalAffectedRowCount
    }

    fun login(input: SysUserLoginSpec): SysUserLoginView? {
        // 根据用户名和密码查询
        val user = sqlClient.executeQuery(entityClass) {
            where(input)
            select(table)
        }.firstOrNull()
        if (user == null) {
            throw BusinessException.create(BusinessCode.user_not_exist.message)
        }
        val token = sysUserTokenService.applyToken(user.id)
        return SysUserLoginView(
            id = user.id,
            token = token.token,
            username = user.username,
            mobile = user.mobile,
            deptId = user.dept?.id,
            expireAt = token.expireAt.toString()
        )
    }


}